package at.fhh.se.tjr.client.controller;

import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import at.fhh.se.tjr.client.model.MoteWrapper;
import at.fhh.se.tjr.client.model.ReceiverThread;
import at.fhh.se.tjr.client.view.MainWindow;
import at.fhhagenberg.se.tjr.protocol.CheckTrafficJam;
import at.fhhagenberg.se.tjr.protocol.Message;
import at.fhhagenberg.se.tjr.protocol.TraceHandlerMessage;
import at.fhhagenberg.se.tjr.protocol.TraceMessage;
import at.fhhagenberg.se.tjr.protocol.TrafficJamAhead;
import at.fhhagenberg.se.tjr.protocol.TrafficJamMessage;

import com.sentilla.host.client.HostClient;
import com.sentilla.net.BroadcastAddress;
import com.sentilla.net.Sender;
import com.sentilla.net.SenderDriver;

public class Controller implements ActionListener {

	private Map<Long, MoteWrapper> motes = new HashMap<Long, MoteWrapper>();

	private final HostClient hostClient = new HostClient();

	private Sender sender;

	private Set<Message> messageQueue = new HashSet<Message>();

	private static Controller instance;

	private ReceiverThread receiverT = new ReceiverThread();

	private TraceHandlerMessage handlerMessage = new TraceHandlerMessage(false);

	private List<TrafficJamMessage> tjMessages = new ArrayList<TrafficJamMessage>();

	private long currentRandomId;

	private MainWindow mainWindow;

	public static final Font FONT = new Font("Verdana", Font.BOLD, 18);
	
	private Controller() {
		try {
			hostClient.connect();
			sender = SenderDriver.create(new BroadcastAddress(), "local");
			receiverT.start();
			mainWindow = new MainWindow(this);
			mainWindow.repaint();
			newRandomId();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static Controller getInstance() {
		if (instance == null)
			instance = new Controller();
		return instance;
	}

	public void processQueue() {

		Iterator<Message> it = messageQueue.iterator();
		try {
			Message msg = it.next();
			MoteWrapper wrapper;
			if (msg instanceof TraceMessage) {
				TraceMessage traceMsg = (TraceMessage) msg;
				if (getMotes().containsKey(traceMsg.getMoteId())) {
					wrapper = getMotes().get(traceMsg.getMoteId());
				} else {
					wrapper = new MoteWrapper(traceMsg.getMoteId());
					getMotes().put(wrapper.getId(), wrapper);
				}
				try {
					Method m = wrapper.getClass().getMethod(
							traceMsg.getMethod(), Long.class);
					m.invoke(wrapper, traceMsg.getData());
				} catch (Exception e) {
					e.printStackTrace();
				}
				if (mainWindow.getWrapperPanel().getWrapper() == null)
					mainWindow.getWrapperPanel().setWrapper(wrapper);
			} else if (msg instanceof TrafficJamMessage) {
				getTjMessages().add((TrafficJamMessage) msg);
			}
			it.remove();
			mainWindow.getMessagesPanel().removeMessage();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void changeDistance(long newDistance){
		mainWindow.getWrapperPanel().setDistance(newDistance);
	}
	
	public void registerID(long newId) {
		mainWindow.getWrapperPanel().registerID(newId);
	}
	
	public void addMessageToTable(Message m){
		mainWindow.getMessagesPanel().addMessage(m);
	}

	Random random = new Random();

	public void sendCheckTrafficJamMsg() {
		CheckTrafficJam msg = new CheckTrafficJam(getCurrentRandomId());
		sender.send(msg);
	}

	public void sendTrafficJamAheadMsg() {
		TrafficJamAhead msg = new TrafficJamAhead(getCurrentRandomId());
		sender.send(msg);
	}

	public void newRandomId() {
		setCurrentRandomId(random.nextLong());
	}

	public void toggleTracing() {
		handlerMessage.setActivate(!handlerMessage.isActivate());
		sender.send(handlerMessage);
	}

	public HostClient getHostClient() {
		return hostClient;
	}

	public Set<Message> getMessageQueue() {
		return messageQueue;
	}

	public Map<Long, MoteWrapper> getMotes() {
		return motes;
	}

	public Sender getSender() {
		return sender;
	}

	public List<TrafficJamMessage> getTjMessages() {
		return tjMessages;
	}

	public long getCurrentRandomId() {
		return currentRandomId;
	}

	public void setCurrentRandomId(long currentRandomId) {
		this.currentRandomId = currentRandomId;
	}

	public void actionPerformed(ActionEvent event) {
		if (event.getSource().equals(mainWindow.getNaviPanel().getNextMessage())) {
			this.processQueue();
		}else if(event.getSource().equals(mainWindow.getNaviPanel().getSendCheckMsg())){
			this.sendCheckTrafficJamMsg();
		}else if (event.getSource().equals(mainWindow.getNaviPanel().getNewRandomId())){
			this.newRandomId();
		}
	}

	public MainWindow getMainWindow() {
		return mainWindow;
	}

}
